﻿/** 
 * Copyright 2010 NUMKIT.COM (contact: opensource@numkit.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 * 
 * @author 陈超
 * @version 1.0
 */
import flash.external.ExternalInterface;
import mx.utils.Delegate;
import flash.display.BitmapData;
class Node {
	public static var TEXTSIDE_LEFT:Number = 0;
	public static var TEXTSIDE_RIGHT:Number = 1;
	public static var TEXTSIDE_UP:Number = 2;
	public static var TEXTSIDE_DOWN:Number = 3;
	public static var TEXT_ADJUST_X:Number = 1;
	public static var TEXT_ADJUST_Y:Number = -3;
	public static var nodeTextColor:Number = 0xFFFFFF;
	private static var formatter:TextFormat;
	private var x:Number;
	private var y:Number;
	private var aLine:Array;
	//存储相关连线
	private var aEnd:Array;
	//存储连线的端点
	private var autoTextSide:Boolean = false;
	private var posDefined:Boolean = false;
	private var id:String;
	private var type:String;
	private var iconWidth = 0;
	private var iconHeight = 0;
	private var posXFix = 0;
	private var posYFix = 0;
	private var textSide:Number;
	private var name:String = "";
	private var tField:TextField;
	private var mPic:MovieClip;
	private var fontSize:Object;
	private var mc:MovieClip;
	private var mouseListener:Object;
	public function Node(node:XMLNode) {
		if (formatter == undefined) {
			formatter = new TextFormat();
			formatter.size = 12;
			formatter.color = nodeTextColor;
		}
		aLine = new Array();
		aEnd = new Array();
		if (node.nodeName != "node") {
			throw new Error("Not a node node!");
		}
		this.id = node.attributes["id"];
		var pos:String = node.attributes["pos"];
		if (pos != undefined && pos != null && pos != "") {
			var aPos:Array = pos.split(",");
			this.x = Number(aPos[0]);
			this.y = Number(aPos[1]);
			if (!isNaN(this.x) && !isNaN(this.y)) {
				this.posDefined = true;
			}
		}
		for (var child:XMLNode = node.firstChild; child != null; child=child.nextSibling) {
			var nodeName:String = child.nodeName;
			if (nodeName == "type") {
				this.type = child.firstChild.nodeValue;
			} else if (nodeName == "name") {
				this.name = child.firstChild.nodeValue;
			}
		}
		if (id == undefined) {
			throw new Error("node id attribute Not Set!");
		}
		if (name == undefined) {
			throw new Error("name node not set in node node!");
		}
		fontSize = formatter.getTextExtent(name);
	}
	public function draw(mc:MovieClip, is:IconSet):Void {
		this.mc = mc;
		if (is == undefined) {
			posXFix = 0;
			posYFix = 0;
			iconWidth = 14;
			iconHeight = 14;
			if (type == "0") {
				mPic = mc.attachMovie("Type0", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			} else if (type == "1") {
				mPic = mc.attachMovie("Type1", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			} else if (type == "2") {
				mPic = mc.attachMovie("Type2", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			} else if (type == "3") {
				mPic = mc.attachMovie("Type3", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			} else {
				mPic = mc.attachMovie("TypeDf", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			}
		} else {
			var aIconBmp:Array = is.getIconArray();
			var bmp:BitmapData = aIconBmp[type];
			if (bmp == null) {
				//载入图标失败
				posXFix = 0;
				posYFix = 0;
				iconWidth = 32;
				iconHeight = 32;
				mPic = mc.attachMovie("LoadFailed", "mPic", mc.getNextHighestDepth(), {_x:this.x, _y:this.y});
			} else {
				mPic = mc.createEmptyMovieClip("mPic", mc.getNextHighestDepth());
				mPic.attachBitmap(bmp, mPic.getNextHighestDepth());
				posXFix = bmp.width/2;
				posYFix = bmp.height/2;
				iconWidth = bmp.width;
				iconHeight = bmp.height;
				mPic._x = this.x-posXFix;
				mPic._y = this.y-posYFix;
			}
		}
		//添加事件处理  
		mouseListener = new Object();
		mouseListener.onMouseMove = Delegate.create(this, onMouseMove);
		mc.onPress = Delegate.create(this, onPress);
		mc.onRelease = Delegate.create(this, onRelease);
		var textX:Number = 0;
		var textY:Number = 0;
		if (autoTextSide) {
			if (iconWidth*iconHeight>400) {
				textSide = TEXTSIDE_DOWN;
			} else {
				textSide = TEXTSIDE_RIGHT;
			}
		}
		if (textSide == TEXTSIDE_UP) {
			textX = this.x-fontSize.textFieldWidth/2;
			textY = this.y-iconHeight/2-fontSize.textFieldHeight-TEXT_ADJUST_Y;
		} else if (textSide == TEXTSIDE_DOWN) {
			textX = this.x-fontSize.textFieldWidth/2;
			textY = this.y+iconHeight/2+TEXT_ADJUST_Y;
		} else if (textSide == TEXTSIDE_LEFT) {
			textX = this.x-iconWidth/2-fontSize.textFieldWidth-TEXT_ADJUST_X;
			textY = this.y-fontSize.textFieldHeight/2;
		} else if (textSide == TEXTSIDE_RIGHT) {
			textX = this.x+iconWidth/2+TEXT_ADJUST_X;
			textY = this.y-fontSize.textFieldHeight/2;
		} else {
			throw new Error("Invalid textSide!");
		}
		tField = mc.createTextField("tField", mc.getNextHighestDepth(), textX, textY, fontSize.textFieldWidth, fontSize.textFieldHeight);
		tField.selectable = false;
		tField.text = name;
		tField.setTextFormat(formatter);
		adjustTextSide();
	}
	public function onPress():Void {
		mc.startDrag(false);
		Mouse.addListener(mouseListener);
	}
	public function onRelease():Void {
		this.x = mPic._x+mc._x+posXFix;
		this.y = mPic._y+mc._y+posYFix;
		Mouse.removeListener(mouseListener);
		mc.stopDrag();
		adjustTextSide();
		this.updateEnds();
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			for (var j:Number = 0; j<aSubLine.length; j++) {
				var currentLine:Line = aSubLine[j];
				var otherEnd:Node = currentLine.getTheOtherEnd(this);
				if (otherEnd == undefined) {
					throw new Error("Can't find the other end when mouse release!");
				}
				otherEnd.updateEnds();
				currentLine.repaint();
			}
		}
		ExternalInterface.call(Constants.NodeClickCallBack, Constants.FlashObjID, id, name, this.x, this.y);
	}
	public function onMouseMove():Void {
		this.x = mPic._x+mc._x+posXFix;
		this.y = mPic._y+mc._y+posYFix;
		adjustTextSide();
		this.updateEnds();
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			for (var j:Number = 0; j<aSubLine.length; j++) {
				var currentLine:Line = aSubLine[j];
				var otherEnd:Node = currentLine.getTheOtherEnd(this);
				if (otherEnd == undefined) {
					throw new Error("Can't find the other end when mouse move!");
				}
				otherEnd.updateEnds();
				currentLine.repaint();
			}
		}
	}
	public function setAutoTextSide(auto:Boolean):Void {
		this.autoTextSide = auto;
	}
	public function setTextSide(side:Number):Void {
		this.textSide = side;
	}
	public function addLine(line:Line):Void {
		//判断所添加线是否包含this节点
		if (line.getNodeA() != this && line.getNodeB() != this) {
			return;
		}
		//判断重复添加                     
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			for (var j:Number = 0; j<aSubLine.length; j++) {
				var currentLine:Line = aSubLine[j];
				if (currentLine == line) {
					return;
				}
			}
		}
		//可以添加
		var done:Boolean = false;
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			var aSubEnd:Array = aEnd[i];
			for (var j:Number = 0; j<aSubLine.length; j++) {
				var currentLine:Line = aSubLine[j];
				//var currentEnd:Point=aSubEnd[j];
				if (currentLine.hasSameEndsWith(line)) {
					aSubLine.push(line);
					aSubEnd.push(new Point(0, 0));
					done = true;
					break;
				}
			}
			if (done) {
				break;
			}
		}
		if (!done) {
			var aParLine:Array = new Array();
			//同端点平行线数组
			var aParEnd:Array = new Array();
			//对应于线的端点数组
			aParLine.push(line);
			aParEnd.push(new Point(0, 0));
			aLine.push(aParLine);
			aEnd.push(aParEnd);
		}
	}
	public function updateEnds():Void {
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			var aSubEnd:Array = aEnd[i];
			var parLineCount:Number = aSubLine.length;
			if (parLineCount == 0) {
				continue;
			} else if (parLineCount == 1) {
				var end:Point = aSubEnd[0];
				end.setX(this.x);
				end.setY(this.y);
			} else {
				var otherEnd:Node = aSubLine[0].getTheOtherEnd(this);
				if (otherEnd == undefined) {
					throw new Error("Can't find the other end when updateEnds!");
				}
				var r:Number = (parLineCount-1)*10/2;
				var d:Number = Math.sqrt(Math.pow(this.x-otherEnd.x, 2)+Math.pow(this.y-otherEnd.y, 2));
				if (d == 0) {
					continue;
				}
				var dX:Number = (otherEnd.y-this.y)*r/d;
				var dY:Number = (this.x-otherEnd.x)*r/d;
				var fromX:Number = this.x+dX;
				var fromY:Number = this.y+dY;
				var toX:Number = this.x-dX;
				var toY:Number = this.y-dY;
				//from 和 to 的调整,防止线交叉
				if (fromX == toX) {
					//横向平行线
					if (fromY>toY) {
						var temp:Number;
						temp = fromY;
						fromY = toY;
						toY = temp;
					}
				} else if (fromY == toY) {
					//竖向平行线
					if (fromX>toX) {
						var temp:Number;
						temp = fromX;
						fromX = toX;
						toX = temp;
					}
				} else {
					if (fromY>toY) {
						var temp:Number;
						temp = fromX;
						fromX = toX;
						toX = temp;
						temp = fromY;
						fromY = toY;
						toY = temp;
					}
				}
				var stepX:Number = (toX-fromX)/(parLineCount-1);
				var stepY:Number = (toY-fromY)/(parLineCount-1);
				for (var j:Number = 0, cX:Number = fromX, cY:Number = fromY; j<aSubLine.length; j++, cX += stepX, cY += stepY) {
					var currentLine:Line = aSubLine[j];
					var currentEnd:Point = aSubEnd[j];
					currentEnd.setX(cX);
					currentEnd.setY(cY);
				}
			}
		}
	}
	public function getEndPos(line:Line):Point {
		for (var i:Number = 0; i<aLine.length; i++) {
			var aSubLine:Array = aLine[i];
			for (var j:Number = 0; j<aSubLine.length; j++) {
				var currentLine:Line = aSubLine[j];
				if (currentLine == line) {
					var aSubEnd:Array = aEnd[i];
					var currentEnd:Point = aSubEnd[j];
					return new Point(currentEnd.x, currentEnd.y);
				}
			}
		}
		return undefined;
	}
	public function getName():String {
		return name;
	}
	public function isPosDefined():Boolean {
		return this.posDefined;
	}
	public function setX(xPos:Number):Void {
		this.x = xPos;
	}
	public function setY(yPos:Number):Void {
		this.y = yPos;
	}
	public function getX():Number {
		return x;
	}
	public function getY():Number {
		return y;
	}
	public function getPos():Point {
		return new Point(x, y);
	}
	public function getMC():MovieClip {
		return mc;
	}
	public function getID():String {
		return id;
	}
	public function shiftRight():Void {
		if (textSide == TEXTSIDE_RIGHT) {
			return;
		}
		tField._x = mPic._x+posXFix+iconWidth/2+TEXT_ADJUST_X;
		tField._y = mPic._y+posYFix-fontSize.textFieldHeight/2;
		textSide = TEXTSIDE_RIGHT;
	}
	public function shiftLeft():Void {
		if (textSide == TEXTSIDE_LEFT) {
			return;
		}
		tField._x = mPic._x+posXFix-iconWidth/2-fontSize.textFieldWidth-TEXT_ADJUST_X;
		tField._y = mPic._y+posYFix-fontSize.textFieldHeight/2;
		textSide = TEXTSIDE_LEFT;
	}
	public function shiftDown():Void {
		if (textSide == TEXTSIDE_DOWN) {
			return;
		}
		tField._x = mPic._x+posXFix-fontSize.textFieldWidth/2;
		tField._y = mPic._y+posYFix+iconHeight/2+TEXT_ADJUST_Y;
		textSide = TEXTSIDE_DOWN;
	}
	public function shiftUp():Void {
		if (textSide == TEXTSIDE_UP) {
			return;
		}
		tField._x = mPic._x+posXFix-fontSize.textFieldWidth/2;
		tField._y = mPic._y+posYFix-iconHeight/2-fontSize.textFieldHeight-TEXT_ADJUST_Y;
		textSide = TEXTSIDE_UP;
	}
	private function adjustTextSide():Void {
		if (textSide == TEXTSIDE_UP) {
			//if (this.y<iconHeight/2+TEXT_ADJUST_Y+fontSize.textFieldHeight) {//边界限制
			if (this.y<Stage.height-iconHeight/2-TEXT_ADJUST_Y-fontSize.textFieldHeight) {
				shiftDown();
			}
		} else if (textSide == TEXTSIDE_DOWN) {
			if (this.y>Stage.height-iconHeight/2-TEXT_ADJUST_Y-fontSize.textFieldHeight) {
				shiftUp();
			}
		} else if (textSide == TEXTSIDE_LEFT) {
			//if (this.x<iconWidth/2+TEXT_ADJUST_X+fontSize.textFieldWidth) {//边界显示
			if (this.x<Stage.width-iconWidth/2-TEXT_ADJUST_X-fontSize.textFieldWidth) {
				shiftRight();
			}
		} else if (textSide == TEXTSIDE_RIGHT) {
			if (this.x>Stage.width-iconWidth/2-TEXT_ADJUST_X-fontSize.textFieldWidth) {
				shiftLeft();
			}
		}
	}
}
